秒杀项目学习笔记 第六章————接口优化

秒杀项目学习笔记 第六章————接口优化

1.redis预减库存 减少数据库访问
2.内存标记减少redius访问
3.请求先入队缓冲,异步下单,增强用户体验 MQ
4.RabbitMQ安装与springBoot集成
5.Nginx水平扩展
5.压测

分库分表中间件 : mycat

秒杀接口优化

思路:减少数据库访问
1.系统初始化,把商品库存数量加载到Redis
2.收到请求,Redis预减库存,库存不足,直接返回,否则继续
3.请求入队,立即返回排队中响应。异步操作,(成功失败不明,只是在排队)

以下两部并发进行
4.服务端:请求出队,生成订单,减少库存
5.客户端:收到排队中消息之后,会轮询,是否秒杀成功

6-2 RabbitMq安装

安装erlang依赖
安装RabbitMq

https://blog.csdn.net/zxl646801924/article/details/80435231
https://blog.csdn.net/weixin_39735923/article/details/79288578

6-2 RabbitMq集成

若要远程访问,需要配置一个rabbitMq配置

1.添加spring-boot-stater-amqp依赖
在pom和application.property中加入依赖和设置参数

MQConfig中配置队列

2.创建消息接受者
新建rabbitmq包,创建MQsender类,属于服务类。
3.创建消息发送者
创建MQReceiver类

一个空格引发的惨案:在application.property中的路径上多加了个空格,导致浪费两小时找BUG,所以路径一定要注意了

注入MQSender实例(作为service),sender.send("hello,imooc");
重点!!: MQSender会引入amqpTemplate

amqpTemplate.convertAndSend(MQConfig.QUEUE, msg);参数:队列名,所传数据
这里不直接写“queue”,而是选用MQConfig中的常量来设置名字

6-4 RabbitMQ四种交换方式

  1. DIRECT模式(直连交换机):消息被发送的时候,需要指定一个binding_key,被这个交换机送到指定的队列里面去。
  2. Topic模式:因为直连交换机,多队列情况需要绑定很多,不方便管理。发送到主题交换机上的消息需要携带指定规则的
    1
    2
    3
    4
    5
    6
    7
     3. Fanout模式 广播模式 发送给**所有绑定在自己身上**的队列。(不需要思考,最快)
    4. Headers 模式路由器和交换机路由的规则是通过Headers信息来交换的,这个有点像HTTP的Headers,将一个交换机声明成首部交换机,绑定一个队列的时候,定义一个Hash的数据结构,消息发送的时候,会携带一组hash数据结构的信息,当Hash的内容匹配上的时候,消息就会被写入队列。



    ## **DIRECT模式:** 没有交换机Exchange
    ```amqpTemplate.convertAndSend(MQConfig.QUEUE, msg);

Topic模式: 交换机Exchange

先将消息发送到交换机上,在由其发送到队列上,相当于做了个路由。

实现:

MQSender的sendTopic方法中,convertAndSend此时参数不同,多了个”topic.key1”,这是路由匹配的字符串

1
2
amqpTemplate.convertAndSend(MQConfig.TOPIC_EXCHANGE, "topic.key1", msg+"1");
amqpTemplate.convertAndSend(MQConfig.TOPIC_EXCHANGE, "topic.key2", msg+"2");

这样匹配到的队列就不同了!!

有两个队列,topicQ1 topicQ2。传入字符串name构造。
有两个topicExchange1 , topicExchange2 。传入字符串name构造。
有两个绑定Binding。将topicQ和topicExchange绑定

topicExchange和是org.springframework.amqp.core中提供的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
MQConfig的实现
*/
@Bean
public Binding topicBinding1() {
return BindingBuilder.bind(topicQueue1()).to(topicExchage()).with("topic.key1");
//bind(队列实例.to(topicExchange实例).with(routingKey)
//routingKey是路由匹配的字符串
}
@Bean
public Binding topicBinding2() {
return BindingBuilder.bind(topicQueue2()).to(topicExchage()).with("topic.#");
// *表示1个单词,#表示0个或多个,也就是这里会发送给多个队列
}

Fanout模式 交换机Exchange 广播模式

向所有队列分发

原因:

6-5 秒杀接口优化

思路:减少数据库访问
1.系统初始化,把商品库存数量加载到Redis
2.收到请求,Redis预减库存,库存不足,直接返回,否则继续(redis库存为0后,之后对数据库请求几乎为0)
3.请求入队,立即返回排队中响应。异步操作,(成功失败不明,只是在排队)

以下两部并发进行
4.服务端:请求出队,生成订单,减少库存。订单写入缓存
5.客户端:收到排队中消息之后,会轮询,询问缓存 是否秒杀成功


秒杀流程:
MiaoshaController
1.afterPropertiesSet()系统初始化,把所有商品库存数量加载到Redis
2.注解实现user通过token注入,判断是否登录
4.判断内存库存标记map,map对应商品标记over是否为true,是则直接返回错误。
3.判断redis缓存库存,预减库存。库存为<0时,设置map对应商品标记为true
4.判断redis缓存订单,是否存在,表示已秒杀。
5.user和goodsid封装到message,由mqSender发送消息。
6.return Result.success(0);//表示排队中

MQSender
1.将MiaoshaMessage给beanToString,传输string消息
2.发送消息amqpTemplate.convertAndSend(MQConfig.MIAOSHA_QUEUE, msg);

MQReceiver
1.MQReceiver已绑定队列,将消息还原成BEAN,得到goodsId和user
2.根据goodsId生产GoodsVo,判断GoodsVo库存(数据库)
3.根据goodsId和user查询order,判断是否已经存在订单(是否已秒杀)(数据库)
4.miaoshaService.miaosha(user, goods)

MiaoshaService
1.调用数据库,减库存。goodsService.reduceStock的DAO操作Update要满足,stock>0,返回 success
2.根据success,决定是否新建order订单(不是miaoshaOrder)

客户端:
接收到0,轮询服务端

负载到25 2534

6-7 压力测试对比

nginx 反向代理

监听80端口,转发给 集群

负载均衡
转发给本机 weight = 1
转发给其他服务器 weight = 2

探活机制
max_fail = 2 最多允许失败两次

LVS:集成到linux内核了,分发给

Powered by Hexo and Hexo-theme-hiker

Copyright © 2017 - 2019 Jae's blog All Rights Reserved.

UV : | PV :